package org.lewis.demo.utils;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RsaUtil {

    public static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0EtweEUEztdWBSJYD/4mMh0tY0BnSXgiQFeXltf7wcLGOxsPhWtmduyzNoF0G5ig96elURX7vaaWgWDgvN0MqkKpeNoosRdr9HXn6vqWdHGTQ0cf2E4J2PQGwb32WnaHWXRitTHeDdmswkQqP2ud55oG+LAvdj//aov8Ju0vmrQIDAQAB";

    public static final String PRIVATE_KEY = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALQS3B4RQTO11YFIlgP/iYyHS1jQGdJeCJAV5eW1/vBwsY7Gw+Fa2Z27LM2gXQbmKD3p6VRFfu9ppaBYOC83QyqQql42iixF2v0defq+pZ0cZNDRx/YTgnY9AbBvfZadodZdGK1Md4N2azCRCo/a53nmgb4sC92P/9qi/wm7S+atAgMBAAECgYA4tjfcwFJolrvHG7UjTTdkqrdwIRoAxtyrhDoDPm4sC1HgRXkrYBFpO6nAmOCza4kA9solYD256Ovgs+f99smP9p/mfIfKTd3BqheYvs0H5fzti+cOZfiaclNPU4bEQijdhp97O91OQ04rMfrjS2Tj0E0B3LdJyF6hrmzF9W9oAQJBAOeDi/wM+HG8jK1PAoOx+AZizjYMKJ+1oEdFekF/97kYOuyt8Id2K0a/BkWzu91E5kol8aSeMiz0hW7y3EQCZv0CQQDHHoWr0z6sVDmRl0m2tnB1mcfB+i+4xhVUBs7mq/YZjyrsrvsj9Oo80IAFzm2DSeEj47XJAHEMBNuXF9TuF4VxAkB5N20x+XCTzI8zpuzAG4yre0xRDCixBp328y/B38jKxx8DEUehBYQ/NIGKOUMh5ZNWO2u8L4BB/X1nzAz8Ju3ZAkBf0KAh/pS5+A17sYEXGtMiw80L2of8MdUxidUlyrmxsuLE4a6XrtLIUMxJ/vtToclkq75d6oh7cBr6qc0chNUBAkA48ABJoFAKmA1CA6GKwiOfzxAVMeqW8C61OYPFYUmBlK+Sib/Dc5z3t8RWRFUGwo+5ZPd+xEEM2ZSXicQG3Tv1";

    /**
     * 加密
     *
     * @param content 明文
     * @return
     */
    public static String encrypt(String content) throws Exception {
        return encrypt(content, getPublicKey(PUBLIC_KEY));
    }

    /**
     * 解密
     *
     * @param content 密文
     * @return
     * @throws Exception
     */
    public static String decrypt(String content) throws Exception {
        return decrypt(content, getPrivateKey(PRIVATE_KEY));
    }

    /**
     * 加密
     *
     * @param content 明文
     * @param publicKey 公钥
     * @return
     * @throws Exception
     */
    private static String encrypt(String content, PublicKey publicKey) throws Exception {
        byte[] bytes = doFinal(content.getBytes(StandardCharsets.UTF_8), publicKey, Cipher.ENCRYPT_MODE);
        return Base64.getEncoder().encodeToString(bytes);
    }

    /**
     * 解密
     *
     * @param content 密文
     * @param privateKey 私钥
     * @return
     * @throws Exception
     */
    private static String decrypt(String content, PrivateKey privateKey) throws Exception {
        byte[] bytes = doFinal(Base64.getDecoder().decode(content), privateKey, Cipher.DECRYPT_MODE);
        return new String(bytes);
    }

    private static byte[] doFinal(byte[] content, Key key, int mode) throws GeneralSecurityException {
        Security.addProvider(new BouncyCastleProvider());
        Cipher cipher = Cipher.getInstance("RSA/NONE/NoPadding");
        cipher.init(mode, key);
        return cipher.doFinal(content);
    }

    /**
     * 生成密钥对
     *
     * @return
     * @throws Exception
     */
    private static KeyPair getKeyPair() throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(512); // 可以理解为：加密后的密文长度，实际原文要小些 越大 加密解密越慢
        return keyGen.generateKeyPair();
    }

    private static PrivateKey getPrivateKey(String privateKey) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(privateKey.getBytes(StandardCharsets.UTF_8));

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");

        return kf.generatePrivate(keySpec);
    }

    private static PublicKey getPublicKey(String publicKey) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(publicKey.getBytes(StandardCharsets.UTF_8));

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");

        return kf.generatePublic(keySpec);
    }

    public static void main(String[] args) throws Exception {
        String src = "123456789987654321";
        System.out.println("原字符串：" + src);

        // 加密
        String encrypt = encrypt(src);
        System.out.println("加密后：" + encrypt);

        // 解密
        String decrypt = decrypt(encrypt);
        System.out.println("再解密：" + decrypt);

        System.out.println("对比结果：" + decrypt.equals(src));
    }

}
